#include "RoceSenderManager.h"
#include <iostream>
#include <unistd.h>

namespace ai_sim {

RoceSenderManager::RoceSenderManager(int mss) 
{
  sendMss = mss;
  curMaxPktSeq = 0;
  segments.clear();
  sendNext = 0;
  sendUna = 0;
  lastClearedSeq  = 0;
}


SegmentInfo* RoceSenderManager::getNextSegment() {
  if(sendNext+1<=segments.size()){
    // std::cout<<" isLastSegment: "<<segments[sendNext].isLastSegment<<" seqNum: "<< segments[sendNext].seqNum<<" segmentSize "<<segments[sendNext].segmentSize<<endl;
    // std::cout<<"["<<sendNext<<","<<segments.size()<<"]"<<endl;
    return &segments[sendNext++];
  }
  else
    return nullptr;
}

void RoceSenderManager::putLargeChunk(const ai_sim::Flow& flow) {
  sliceChunk(flow);
}

void RoceSenderManager::handleAck(uint32_t seqNum) {
  sendUna = seqNum;
  doClear();
}



void RoceSenderManager::handleNack(uint32_t seqNum) {
  sendNext = seqNum;
}

bool RoceSenderManager::isSendCompleted() {
  return sendUna >= curMaxPktSeq;
  // return sendUna >= sendNext;
}

void RoceSenderManager::doClear() {
  uint32_t ackedButUnclear = sendUna - lastClearedSeq;
  if (ackedButUnclear > CLEAR_ACKED_SEGMENT_THRESHOLD) {
    for (uint32_t i = 0; i < ackedButUnclear; i++)
      if (segments.count(lastClearedSeq)) {
        segments.erase(lastClearedSeq);
        ++lastClearedSeq;
      }
  }
  
}
void RoceSenderManager::sliceChunk(const ai_sim::Flow& flow) {
  int size = flow.data_size;
  while(size > 0) { // eg: flow size 512 < mss 1000, so the flow has only one packet
    bool lastSeg = ((size - sendMss <= 0) ? true : false);
    int segSize = (size - sendMss >= 0 ? sendMss : size);
    size -= segSize;

    segments.insert({curMaxPktSeq, {flow, lastSeg, curMaxPktSeq, segSize}});
    ++curMaxPktSeq;
  }
}

}